package socket;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//聊天室服务端
public class Server {
    /*
    java.net.ServerSocket
    运行在服务端的ServerSocket主要任务：
    1.向服务端申请服务端口，客户端就是通过端口与服务端建立连接的
    2.监听服务端口，一段一个客户端连接了就会立即创建一个Socket实例与之交互
    我们将ServerSocket比喻为某客服中心的“总机”
     */
    private ServerSocket serverSocket;

    public Server() {
        try {
            System.out.println("正在启动服务端");
            /*
            如果端口被其他程序占用了，则会抛出异常：
            java.net.BindException:address already in use
            解决办法：
            1.杀死占用该端口的进程（通常发生在服务端启动两次导致）
            2.更换端口号
             */
            serverSocket = new ServerSocket(8088);
            System.out.println("服务端启动完毕！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            System.out.println("等待客户端连接...");
            /*
            ServerSocket提供的重要方法：
            socket accept（）
            用于接收客户端的连接，并返回一个Socket实例与连接的客户端交互
            该方法是一个阻塞方法，调用程序会“卡住”,直到一个客户端连接为止
             */
            Socket socket = serverSocket.accept();
            System.out.println("一个客户端连接了");
            //启动一个线程来与该客户端交互
            ClientHander handler=new ClientHander(socket);
            Thread t=new Thread(handler);
            t.start();
            /*
            Socket提供的方法
            InputStream getInputStream（）
            获取的字节输入流用于读取来自远端计算机发送过来的数据
             */
            InputStream in = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(
                    in, StandardCharsets.UTF_8);
            BufferedReader br = new BufferedReader(isr);
            //读取来自客户端发过来的一行字符串
            String line;
            /*
            当我们通过BufferedReader的readLine方法读取来自‘远端计算机发送
            过来一行字符串时，该方法首先会阻塞等待对方发送内容，一旦对方发送
            过来一行字符串此时该方法会立即将这样的字符串内容返回
            如果远端计算机断开连接：
            远端计算机正常断开（进行了TCP挥手动作）此时readLine方法会立即返回null，表达流读取到了末尾
            远端计算机异常断开（没有进行TCP挥手动作，意外终止）此时readLine方法
            会立即抛出异常：java.net.SocketException:Connection reset
             */
            while ((line = br.readLine()) != null) {
                System.out.println("客户端说：" + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
    /*
    该线程任务是负责与指定的客户端进行交互
     */
    private class ClientHander implements Runnable{
        private Socket socket;
        public ClientHander(Socket socket){
            this.socket=socket;
        }
        public void run(){
            try {
                InputStream in=socket.getInputStream();
                InputStreamReader isr=new InputStreamReader(in,StandardCharsets.UTF_8);
                BufferedReader br=new BufferedReader(isr);
                String line;
                /*...*/
                while ((line=br.readLine())!=null){
                    System.out.println("客户端说："+line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
